home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / Snippets / Devices / Disable Power Off Key / PatchPowerOff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-20  |  6.0 KB  |  209 lines  |  [TEXT/CWIE]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Sample code demonstrating how to patch PowerOff key
  5. **
  6. **    by Brian Bechtel, Apple Developer Technical Support
  7. **
  8. **    File:        PatchPowerOff.c
  9. **
  10. **    Copyright © 1995 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DTS Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21. #include <Gestalt.h>
  22. #include <Resources.h>
  23. #include <Errors.h>
  24. #include <OSUtils.h>
  25. #include <Traps.h>
  26. #include <SetupA4.h>
  27. #include <A4Stuff.h>
  28.  
  29. /* from the 7.5.3 tech note */
  30. #ifdef PowerPC
  31. enum {
  32.     uppPowerOffProcInfo = kPascalStackBased
  33.         | STACK_ROUTINE_PARAMETER(1, kTwoByteCode)
  34.         | STACK_ROUTINE_PARAMETER(2, kTwoByteCode)
  35. };
  36. #endif
  37.  
  38. /* constants used as parameters to the power off key routine */
  39. enum {
  40.     kPowerKey  = 0x7F,
  41.     kDissablePwKy = 0x6B,
  42.     kEnablePwKy = 0x00,
  43.  
  44.     kShutdownDlog = 0x7E,
  45.     kNoDismiss = 0x00,
  46.     kOneSecond = 0x70,
  47.     kTenSeconds = 0x400
  48. };
  49.  
  50. /* declaration for the power off key routine */
  51. typedef pascal OSErr (*PwrKeyProc)(short item, short action);
  52.  
  53. /* for debugging */
  54. #define assert(i) if ((i) DebugStr("\p;printf \"assertion failed file %s line %d\" __FILE__, __LINE__")
  55.  
  56. #define kINITid            0    /* matches the resID in the 68K Project preferences */
  57. #define kICONid            128
  58.  
  59. pascal void ShowIcon7(short iconId, Boolean advance);
  60.  
  61. // local function declarations
  62. void InitAlertPatch(void);
  63. void ClearAlertPatch(void);
  64. void asm AlertPatch(void);
  65. OSErr DisablePowerOffKey(void);
  66. void main(void);
  67.  
  68. static long        gOriginalTrapPtr = 0;
  69. static Boolean    gAlertPatchIsInstalled = false;
  70.  
  71. /*
  72.  * InstallAlertPatch
  73.  * This routine patches the Alert() trap so that we can check for
  74.  * the PowerOff alert and dismiss it before it comes up.
  75.  */
  76. void InitAlertPatch(void)
  77. {
  78.     if (gAlertPatchIsInstalled == false)
  79.     {
  80.         gOriginalTrapPtr = (long) NGetTrapAddress( _Alert, ToolTrap);
  81.         NSetTrapAddress( (UniversalProcPtr)(AlertPatch), _Alert, ToolTrap);
  82.         gAlertPatchIsInstalled = true;
  83.     }
  84. }
  85.  
  86. /*
  87.  * ClearAlertPatch
  88.  * This routine clears out the patch we installed in InstallAlertPatch.
  89.  * Note: Never call this routine from within an extension; you don't know
  90.  * what other patches may have been put on Alert() after you installed
  91.  * your patch, and bad things would happen if you eliminate yourself from
  92.  * the chain of patches...
  93.  */
  94. void ClearAlertPatch(void)
  95. {
  96.     if (gAlertPatchIsInstalled == true)
  97.     {
  98.         NSetTrapAddress( (UniversalProcPtr)(gOriginalTrapPtr), _Alert, ToolTrap);
  99.         gAlertPatchIsInstalled = false;
  100.     }
  101. }
  102.  
  103. /*
  104.  * AlertPatch
  105.  * This patch checks to see if we are about to display alert -16500.  This
  106.  * is the ALRT id used by the dialog which asks if you want to shutdown, etc.
  107.  * If we are about to show that dialog, fake things up as if we have already
  108.  * shown the dialog, and the user has pressed the Cancel button.  The result
  109.  * is that the dialog is never shown, and no action is taken.  Just as if
  110.  * the PowerOff code was never added to the system...
  111.  * Call this routine only if the programmatic method (using the 'pwky' Gestalt
  112.  * selector) fails.
  113.  * This patch trashes register a0 and possibly register d0, but
  114.  * these registers are trashed by Alert anyway.
  115.  */
  116. void asm AlertPatch(void)
  117. {
  118. // Check for proper alert.  If it's the trap we want to avoid,
  119. // return to caller without actually executing the Alert trap.
  120. // Set up the stack so it looks as if the user hit okay.
  121.  
  122. PatchPowerOff:
  123. // test for specific PowerOff dialog id.  If we find it, return as if we hit cancel.
  124.     move.w    8(sp), d0    // now d0 has the dialog ID
  125.     cmpi.w    #-16500,d0    // we want to avoid -16500
  126.     bne        exitPatchPowerOff
  127. // if it's the alert we want, return to caller without 
  128. // executing the alert.  
  129. // FUNCTION Alert ( alertID: INTEGER; filterProc: ProcPtr) : INTEGER;
  130. // means that the stack looks like this:
  131. //        sp + 0 -> return address (4 bytes)
  132. //           + 4 -> filterProc (4 bytes)
  133. //           + 8 -> alertID (2 bytes)
  134.     movea.l    (sp)+, a0    // the caller's return address
  135.     lea        6(sp), sp    // clear off the parms put on by caller
  136.     move.w    #2, (sp)    // tell the system we hit cancel. (2nd button = cancel)
  137.     jmp        (a0)        // return to caller without actually calling Alert
  138.     
  139. exitPatchPowerOff:
  140.     // call the original trap.
  141. //First, set up a4 to access the old trap address
  142.     jsr        SetUpA4        // puts old a4 into register d0
  143.  
  144.     lea        gOriginalTrapPtr, a0
  145.  
  146.     exg        d0, a4        // restore old value of a4
  147.     
  148.     movea.l    (a0), a0
  149.     jmp        (a0)    
  150. }
  151.  
  152. /*
  153.  * DisablePowerOffKey
  154.  * This routine will either call the routine pointed to by the Gestalt
  155.  * selector 'pwky', telling it to disable the power off key, or this
  156.  * routine will return an error (usually telling you the Gestalt selector
  157.  * is not installed.)
  158.  */
  159. OSErr DisablePowerOffKey(void) 
  160. {
  161.     OSErr err;
  162.     PwrKeyProc pPwrKey;
  163.     err = Gestalt('pwky', (long*) &pPwrKey);
  164.     if ( (long) pPwrKey == nil )
  165.         err = gestaltUndefSelectorErr;    // no proc ptr means no selector
  166.     if ( err == noErr )
  167. #ifdef PowerPC
  168.         err = CallUniversalProc((UniversalProcPtr) pPwrKey,
  169.             uppPowerOffProcInfo, kPowerKey, kDissablePwKy);
  170. #else
  171.         err = pPwrKey(kPowerKey, kDissablePwKy);
  172. #endif
  173.     return err;
  174. }
  175.  
  176.  
  177. /* main */
  178.  
  179. void main(void)
  180. {
  181.     long    oldA4;
  182.     Handle    h;
  183.     OSErr    err = noErr;
  184.     
  185.     #ifdef USE_DEBUGGER_CALLS
  186.         Debugger();
  187.     #endif
  188.  
  189.     /* set up our A4 context for _this file_ */
  190.     oldA4 = SetCurrentA4();
  191.     RememberA4();
  192.         
  193.     /* First try to disable the power key programmatically.
  194.      * If that doesn't work, do a skanky hack.
  195.      */
  196.     if (DisablePowerOffKey() != noErr)
  197.     {
  198.         /* detach ourselves */
  199.         h = Get1Resource('INIT', kINITid);
  200.         if (h) DetachResource(h);
  201.             
  202.         InitAlertPatch();
  203.     }
  204.     ShowIcon7(kICONid, true);
  205.     
  206.     /* restore the a4 world */
  207.     SetA4(oldA4);
  208. }
  209.